package com.shxzz.shortlink.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.shxzz.shortlink.admin.common.biz.user.UserContext;
import com.shxzz.shortlink.admin.common.convention.exception.ServiceException;
import com.shxzz.shortlink.admin.dao.entity.GroupDO;
import com.shxzz.shortlink.admin.dao.mapper.GroupMapper;
import com.shxzz.shortlink.admin.dto.req.GroupRegisterReqDTO;
import com.shxzz.shortlink.admin.dto.req.GroupSortReqDTO;
import com.shxzz.shortlink.admin.dto.req.GroupUpdateReqDTO;
import com.shxzz.shortlink.admin.dto.resp.GroupRespDTO;
import com.shxzz.shortlink.admin.remote.LinkRemoteService;
import com.shxzz.shortlink.admin.remote.dto.resp.LinkGroupCountRespDTO;
import com.shxzz.shortlink.admin.service.GroupService;
import lombok.RequiredArgsConstructor;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;

/**
 * @author shxzz
 * @create 2023-12-14-14:55
 * @description 短链接分组接口实现类
 */
@Service
@RequiredArgsConstructor
public class GroupServiceImpl extends ServiceImpl<GroupMapper, GroupDO> implements GroupService {

    private final GroupMapper groupMapper;

    private final LinkRemoteService linkRemoteService = new LinkRemoteService(){};

    private static final int GROUP_ID_LENGTH = 6;
    private static final int GROUP_REGISTER_FAILED_MAX_COUNT = 10;

    @Override
    public void register(GroupRegisterReqDTO requireParam) {
        this.registerGroup(UserContext.getUser().getUsername(), requireParam.getName());
    }

    @Override
    public void registerGroup(String username, String groupName) {
        GroupDO groupDO = GroupDO.builder()
                .name(groupName)
                .gid(RandomUtil.randomString(GROUP_ID_LENGTH))
                .username(username)
                .sortOrder(0)
                .build();

        int insert = 0;
        int failed = 0;
        do {
            groupDO.setGid(RandomUtil.randomString(GROUP_ID_LENGTH));
            try {
                insert = groupMapper.insert(groupDO);
            } catch (DuplicateKeyException ex) {
                failed++;
                if (failed > GROUP_REGISTER_FAILED_MAX_COUNT) {
                    throw new ServiceException("短链接分组添加失败");
                }
            }
        } while (insert != 1);
    }

    @Override
    public List<GroupRespDTO> findAllGroupInfo() {
        LambdaQueryWrapper<GroupDO> queryWrapper = Wrappers.lambdaQuery(GroupDO.class)
                .eq(GroupDO::getUsername, UserContext.getUser().getUsername())
                .eq(GroupDO::getDelFlag, 0)
                .orderByDesc(GroupDO::getSortOrder, GroupDO::getUpdateTime);

        // 查询所有分组
        List<GroupDO> groupDOList = groupMapper.selectList(queryWrapper);
        List<String> gids = groupDOList.stream().map(GroupDO::getGid).toList();
        if(CollUtil.isEmpty(gids)) {
            throw new ServiceException("用户无短链接分组信息");
        }

        // 查询每个分组的链接数量
        HashMap<String, Integer> linkGroupCountResult = new HashMap<>(gids.size());
        List<LinkGroupCountRespDTO> linkGroupCountList = linkRemoteService.selectLinkGroupCount(gids)
                .getData();
        if(CollUtil.isEmpty(linkGroupCountList)) {
            throw new ServiceException("短链接组信息查询失败");
        }
        linkGroupCountList.forEach(item -> linkGroupCountResult.put(item.getGid(), item.getLinkCount()));

        // 包装数据返回
        return groupDOList.stream()
                .map(group -> GroupRespDTO.builder()
                        .gid(group.getGid())
                        .name(group.getName())
                        .sortOrder(group.getSortOrder())
                        .shortLinkCount(linkGroupCountResult.get(group.getGid()))
                        .build())
                .toList();
    }

    @Override
    public void update(GroupUpdateReqDTO requireParam) {
        LambdaUpdateWrapper<GroupDO> updateWrapper = Wrappers.lambdaUpdate(GroupDO.class)
                .eq(GroupDO::getUsername, UserContext.getUser().getUsername())
                .eq(GroupDO::getGid, requireParam.getGid());

        GroupDO groupDO = GroupDO.builder()
               .name(requireParam.getName())
               .build();

        groupMapper.update(groupDO, updateWrapper);

    }

    @Override
    public void deleteGroup(String gid) {
        LambdaUpdateWrapper<GroupDO> updateWrapper = Wrappers.lambdaUpdate(GroupDO.class)
                .eq(GroupDO::getUsername, UserContext.getUser().getUsername())
                .eq(GroupDO::getGid, gid)
                .eq(GroupDO::getDelFlag, 0);

        GroupDO groupDO = new GroupDO();
        groupDO.setDelFlag(1);

        groupMapper.update(groupDO, updateWrapper);
    }

    @Override
    public void sortGroup(List<GroupSortReqDTO> requireParam) {

        requireParam.forEach(
                groupSortReqDTO -> {
                    LambdaUpdateWrapper<GroupDO> updateWrapper = Wrappers.lambdaUpdate(GroupDO.class)
                            .eq(GroupDO::getUsername, UserContext.getUser().getUsername())
                            .eq(GroupDO::getGid, groupSortReqDTO.getGid())
                            .eq(GroupDO::getDelFlag, 0);

                    GroupDO groupDO = GroupDO.builder()
                           .sortOrder(groupSortReqDTO.getSortOrder())
                           .build();

                    groupMapper.update(groupDO, updateWrapper);
                }
        );
    }
}
